/*
 * Created on 2005-3-5
 */
package com.hd123.rumba.action;

import java.util.List;

import net.sf.hibernate.HibernateException;

import com.hd123.rumba.cartridge.ICartFunctionView;
import com.hd123.rumba.cartridge.biz.BCartFunctionView;
import com.hd123.rumba.cartridge.biz.IBCartridgeMgr;
import com.hd123.rumba.cartridge.entry.Entry;
import com.hd123.rumba.cartridge.entry.EntryLink;
import com.hd123.rumba.cartridge.entry.EntryLinkStyle;
import com.hd123.rumba.domain.CDomain;
import com.hd123.rumba.domain.IDomainMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.navigation.menu.BMenu;
import com.hd123.rumba.navigation.menu.BMenuItem;
import com.hd123.rumba.navigation.menu.IBMenuMgr;
import com.hd123.rumba.organization.COrganization;
import com.hd123.rumba.request.Action;
import com.hd123.rumba.request.ActionAbstractImpl;
import com.hd123.rumba.request.ActionConstants;
import com.hd123.rumba.request.BuffaloSession;
import com.hd123.rumba.request.GWTModuleDispatcher;
import com.hd123.rumba.request.JspLib;
import com.hd123.rumba.runtime.IAfterLogin;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.ObserverRegistry;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.user.CUser;
import com.hd123.rumba.user.IUserMgr;
import com.hd123.rumba.user.LoginResult;
import com.hd123.rumba.user.User;
import com.hd123.rumba.user.biz.BUser;
import com.hd123.rumba.user.biz.IBUserMgr;
import com.hd123.rumba.util.ClassifiedHashtable;
import com.hd123.rumba.util.SecurityUtil;

/**
 * @author caili
 */
public class ViewApplication extends ActionAbstractImpl implements Action {

  public static final String CAPTION_VIEW = "应用程序";

  private IDomainMgr domainMgr = null;
  private IBCartridgeMgr cartMgr = null;
  private IBMenuMgr menuMgr = null;

  public String execute() throws Exception {
    String url = "application/Login.jsp";
    if (dd.getFormValues().containsKey("start")) {
      String startnode = (String) dd.getFormValues().get("start");
      if (startnode.equals("displayLogin"))
        url = displayLogin();
      else if (startnode.equals("processLogin"))
        return processLogin();
      else if (startnode.equals("siteMenu"))
        url = this.executeWithPermission("viewSiteMenu", null);
      else if (startnode.equals("siteSplitter"))
        url = viewSiteSplitter();
      else if (startnode.equals("top"))
        url = viewGlobalMenu();
      else if (startnode.equals("welcome"))
        return executeWithPermission("welcome", null);
      else if (startnode.equals("loginInfo"))
        return loginInfo();
      else if (startnode.equals("changePwd"))
        return executeWithPermission("changePwd", null);
      else if (startnode.equals("logout"))
        return logout();
      else if (startnode.equals("backToLogin"))
        return backToLogin();
      else if (startnode.equals("displayMainApplicationFrame"))
        return executeWithPermission("displayMainApplicationFrame", null);
      else if ("jump".equals(startnode))
        return jump();
      else if ("dispatch".equals(startnode)) {
        String action = (String) dd.getFormValue("action");
        if ("saveChangePwd".equals(action))
          return executeWithPermission("saveChangePwd", null);
      }
    }
    return url;
  }

  /* logger.event */
  protected static final String EVENT_LOGIN = "登录";
  protected static final String EVENT_LOGOUT = "退出登录";

  private static final String TEMPLATE_MAINFRAME = "application/MainApplicationFrame.jsp";
  private static final String TEMPLATE_TOPBANNER = "application/TopBanner.jsp";
  private static final String TEMPLATE_SITEMENUBAR = "application/SiteMenuBar.jsp";
  private static final String TEMPLATE_SITESPLITTER = "application/SiteMenuSplitter.jsp";
  private static final String TEMPLATE_LOGININFO = "application/LoginInfo.jsp";
  private static final String TEMPLATE_CHANGEPWD = "application/ChangePwd.jsp";
  private static final String TEMPLATE_CHANGEPWDSUCCESS = "application/ChangePwdSuccess.jsp";
  private static final String TEMPLATE_REDIRECT = "application/Redirect.jsp";

  protected String viewSiteSplitter() throws Exception {
    return TEMPLATE_SITESPLITTER;
  }

  protected String viewGlobalMenu() throws Exception {
    this.preloadMgrs();
    dd.put("mainMenu", this.getCurrentMainMenu());

    return TEMPLATE_TOPBANNER;
  }

  public String viewSiteMenu() throws Exception {
    this.preloadMgrs();
    String itemId = (String) dd.getFormValue("itemId");
    BMenu menu = null;
    if (itemId != null) {
      BMenu gmenu = this.getCurrentMainMenu();
      BMenuItem item = gmenu.getItemById(itemId);
      if (item != null)
        menu = menuMgr.cloneSubtree(gmenu, item);
    }

    if (menu != null)
      dd.put("siteMenu", menu);

    return TEMPLATE_SITEMENUBAR;
  }

  protected String loginInfo() throws Exception {
    return TEMPLATE_LOGININFO;
  }

  protected String processLogin() throws Exception {
    String template = "application/Login.jsp";
    dd.validateFormValue("LoginForm_Login", null, true, null, CUser.CAPTION_LOGIN);
    dd.validateFormValue("LoginForm_Password", null, true, "", CUser.CAPTION_PASSWORD);
    dd.validateFormValue("LoginForm_RegistrationDomain", null, false, "",
        COrganization.CAPTION_CLASS + "(" + CDomain.CAPTION_CLASS + ")");
    if (!dd.isFormValid()) {
      if (dd.getInvalidFormValues().containsKey("LoginForm_Login_missing")) {
        dd.addErrorText("请输入登录名。");
      }
      if (dd.getInvalidFormValues().containsKey("LoginForm_Password_missing")) {
        dd.addErrorText("请输入密码。");
      }
      if (dd.getInvalidFormValues().containsKey("LoginForm_RegistrationDomain_missing")) {
        dd.addErrorText("没有指定登录的域，请联系管理员。");
      }
      return template;
    }
    String login = (String) dd.getFormValue("LoginForm_Login");
    String password = (String) dd.getFormValue("LoginForm_Password");
    String tokenValue = (String) dd.getFormValue("LoginForm_Token");
    String domainId = (String) dd.getFormValue("LoginForm_RegistrationDomain");
    IUserMgr userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    LoginResult result = userMgr.login(login, password, tokenValue, domainId);
    if (result.isError()) {
      dd.addErrorText(result.getErrorText());
      return template;
    }
    dd.setCurrentDomain(result.getDomain());
    dd.setCurrentUser(result.getUser());
    dd.setCurrentOrganization(result.getLoginOrganization());
    dd.setEnterpriseDomain(result.getEnterpriseDomain());
    dd.setLoginDomain(result.getDomain());
    dd.setLoginUser(result.getUser());
    BuffaloSession.setSession(dd.getSession());

    ObserverRegistry.notifyObservers(IAfterLogin.class, this);
    logger.info(EVENT_LOGIN, null);

    dd.putFormValue("reDirectUrl", JspLib
        .getAction("ViewApplication?start=displayMainApplicationFrame"));
    template = "rumba/application/Redirect.jsp";
    return template;
  }

  public String displayMainApplicationFrame() {
    return "application/MainApplicationFrame.jsp";
  }

  public String welcome() throws Exception {
    dd.setWorkingTemplate("application/Welcome.jsp");
    return ActionConstants.APPLICATIONFRAME;
  }

  protected String displayLogin() throws Exception {
    setFormValues(null);
    return "application/Login.jsp";
  }

  private void setFormValues(User user) {
    String login = (String) dd.getFormValue("LoginForm_Login");
    String domainId = (String) dd.getFormValue("LoginForm_RegistrationDomain");
    dd.putFormValue("LoginForm_Login", login == null ? "" : login);
    dd.putFormValue("LoginForm_RegistrationDomain", domainId == null ? "" : domainId);
  }

  public String changePwd() throws Exception {
    if (dd.getCurrentDomain() == null || dd.getCurrentUser() == null)
      return backToLogin();
    dd.setWorkingTemplate(TEMPLATE_CHANGEPWD);
    return ActionConstants.APPLICATIONFRAME;
  }

  public String saveChangePwd() throws Exception {
    if (dd.getCurrentDomain() == null || dd.getCurrentUser() == null)
      return backToLogin();
    String oldpwd = (String) dd.validateFormValue("user_oldPwd", null, true, null, "原密码");
    String newpwd = (String) dd.validateFormValue("user_newPwd", null, true, null, "新密码");
    String newpwd2 = (String) dd.validateFormValue("user_newPwd2", null, true, null, "再一次输入的新密码");
    if (!dd.isFormValid())
      return changePwd();
    IBUserMgr userMgr = (IBUserMgr) NamingMgr.getInstance().lookupMgr(IBUserMgr.class);
    BUser buser = userMgr.loadUser(dd.getCurrentUser().getUuid());
    if (buser == null) {
      dd.addErrorText("指定的用户不存在。");
      return changePwd();
    }
    if (!dd.getCurrentUser().getPassword().equals(SecurityUtil.encodeString(oldpwd))) {
      dd.addErrorText("输入的旧密码不正确，请重新输入。");
      return changePwd();
    }

    try {
      buser.setPassword(newpwd);
      buser.setPasswordConfirm(newpwd2);
      ClassifiedHashtable h = userMgr.saveUserT(buser, new OperateContext(dd.getCurrentUser()));
      if (h != null && h.size() > 0) {
        dd.addInvalidFormValues("user_", h);
        return changePwd();
      }
    } catch (BusinessException e) {
      dd.addErrorText(e.getMessage());
      return changePwd();
    } catch (HibernateException e) {
      dd.addErrorText(e.getMessage());
      return changePwd();
    }
    dd.setWorkingTemplate(TEMPLATE_CHANGEPWDSUCCESS);
    return ActionConstants.APPLICATIONFRAME;
  }

  protected String logout() throws Exception {
    if (dd.getCurrentDomain() != null)
      logger.info(EVENT_LOGOUT, null);

    String url = "application/Login.jsp";
    ((IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class)).logout(dd.getCurrentUser());
    setFormValues(null);
    return url;
  }

  protected String backToLogin() throws Exception {
    dd.setCurrentDomain(dd.getLoginDomain());
    dd.setCurrentUser(dd.getLoginUser());
    return TEMPLATE_MAINFRAME;
  }

  protected String jump() throws Exception {
    StringBuffer sb = new StringBuffer();
    sb.append(dd.getRequest().getContextPath());
    sb.append("/");

    String target = (String) dd.getFormValue("target");
    target = GWTModuleDispatcher.getInstance().getModuleURL(target);
    sb.append(target);

    dd.putFormValue("reDirectUrl", sb.toString());
    return TEMPLATE_REDIRECT;
  }

  // /////////////////////////

  /**
   * 预载入所有需要的管理员对象。
   */
  private void preloadMgrs() throws Exception {
    if (domainMgr == null)
      domainMgr = (IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class);
    if (cartMgr == null)
      cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(IBCartridgeMgr.class);
    if (menuMgr == null)
      menuMgr = (IBMenuMgr) NamingMgr.getInstance().lookupMgr(IBMenuMgr.class);
  }

  /**
   * 取得当前用户的主菜单。
   * 
   * @return
   * @throws BusinessException
   */
  private BMenu getCurrentMainMenu() throws Exception {
    List<ICartFunctionView> cfvs = domainMgr.getCFVsByDomain(dd.getCurrentDomain());
    BMenu mainMenu = menuMgr.createMenu();
    for (int i = 0; i < cfvs.size(); i++) {
      BCartFunctionView cfv = cartMgr.getFunctionView(cfvs.get(i).getUuid());
      if (cfv != null)
        mainMenu.merge(cfv.getMainMenu());
    }
    mainMenu.obscurByUser(this.getCurrentUser());
    return mainMenu;
  }

  /**
   * 将指定菜单生成javascript脚本，用于显示顶级菜单。参见TopBanner.jsp。
   * 
   * @param menu
   * @param jsvMenu
   * @param jsvDefItemId
   * @return
   * @throws Exception
   */
  public static final String toJS_TopMenu(BMenu menu, String jsvMenu, String jsvDefItemId)
      throws Exception {
    StringBuffer sb = new StringBuffer();
    sb.append("var mi = null;\n");

    BMenuItem mi = menu.getFirstChild(null);
    if (mi != null)
      sb.append(jsvDefItemId + " = \"" + mi.getId() + "\";\n");
    else
      sb.append(jsvDefItemId + " = null;\n");
    while (mi != null) {
      boolean autoSiteMenu = menu.hasChildren(mi);

      StringBuffer sb2 = new StringBuffer();
      sb2.append("mi = new RTopMenuItem({");
      sb2.append("id: " + JspLib.toJSConst(mi.getId()) + ", ");
      sb2.append("caption: " + JspLib.toJSConst(mi.getCaption()) + ", ");
      sb2.append("hint: " + JspLib.toJSConst(mi.getHint()));
      sb2.append("});\n");
      sb.append(sb2.toString());

      Entry e = mi.getEntry();
      if (e != null)
        for (EntryLink el : e.getLinks()) {
          if (EntryLink.VALUE_TARGET_SITEMENU.equals(el.getTarget()))
            autoSiteMenu = false;
          String url = el.getUrl();
          if (el.getStyle().equals(EntryLinkStyle.action))
            url = JspLib.getAction(url);
          StringBuffer sb3 = new StringBuffer();
          sb3.append("mi.addLink(new RLink({");
          sb3.append("url: \"" + url + "\", ");
          sb3.append("target: " + JspLib.toJSConst(el.getTarget()));
          sb3.append("}));\n");
          sb.append(sb3.toString());
        }

      if (autoSiteMenu) {
        StringBuffer sb4 = new StringBuffer();
        sb4.append("mi.addLink(new RLink({");
        sb4.append("url: \""
            + JspLib.getAction("ViewApplication?start=siteMenu&itemId=" + mi.getId()) + "\", ");
        sb4.append("target: RLink.VALUE_TARGET_SITEMENU");
        sb4.append("}));\n");
        sb.append(sb4.toString());
      }

      sb.append(jsvMenu + ".addItem(mi);\n");
      mi = menu.getNextItem(mi);
    }
    return sb.toString();
  }

  /**
   * 将指定菜单生成javascript脚本，用于显示左边菜单。参见SiteMenuBar.jsp。
   * 
   * @param menu
   * @param jsvMenu
   * @return
   * @throws Exception
   */
  public static final String toJS_SiteMenu(BMenu menu, String jsvMenu) throws Exception {
    if (menu == null)
      return "";
    StringBuffer sb = new StringBuffer();
    sb.append("var mi = new Array();\n");
    sb.append(toJS_SiteMenu_SubMenu(menu, jsvMenu, null, "null"));
    return sb.toString();
  }

  private static final String toJS_SiteMenu_SubMenu(BMenu menu, String jsvMenu,
      BMenuItem parentItem, String jsvParentItem) throws Exception {
    BMenuItem item = menu.getFirstChild(parentItem);
    if (item == null)
      return "";

    StringBuffer sb = new StringBuffer();
    String jsvItem = "mi[" + item.getLevel() + "]";
    sb.append(jsvItem + " = null;\n");

    while (item != null) {
      StringBuffer sb2 = new StringBuffer();
      sb2.append(jsvItem + " = new RSiteMenuItem({");
      sb2.append("id: " + JspLib.toJSConst(item.getId()) + ", ");
      sb2.append("caption: " + JspLib.toJSConst(item.getCaption()) + ", ");
      sb2.append("hint: " + JspLib.toJSConst(item.getHint()));
      sb2.append("});\n");
      sb.append(sb2.toString());

      Entry e = item.getEntry();
      if (e != null && e.getLinks().size() > 0) {
        EntryLink el = e.getLinks().get(0);
        String url = el.getUrl();
        if (el.getStyle().equals(EntryLinkStyle.action))
          url = JspLib.getAction(url);
        StringBuffer sb3 = new StringBuffer();
        sb3.append(jsvItem + ".setLink(new RLink({");
        sb3.append("url: \"" + url + "\", ");
        sb3.append("target: " + JspLib.toJSConst(el.getTarget()));
        sb3.append("}));\n");
        sb.append(sb3.toString());
      }

      sb.append(jsvMenu + ".addItem(" + jsvItem + ", " + jsvParentItem + ");\n");

      sb.append(toJS_SiteMenu_SubMenu(menu, jsvMenu, item, jsvItem));

      item = menu.getNextItem(item);
    }
    return sb.toString();
  }
}
